package pl.enigmatic.math.graph;

import java.util.List;
import java.util.Set;

import pl.enigmatic.HasName;

public class NamedBaseTree<B extends HasName, T extends NamedBaseTree<B, T>>
		extends Tree<B, T> implements HasName {

	protected NamedBaseTree(final B base, final List<B> baseChildren) {
		super(base, baseChildren);
	}

	protected NamedBaseTree(final B base) {
		super(base);
	}

	@Override
	public String getName() {
		return getBase().getName();
	}

	@Override
	public void setName(String name) {
		getBase().setName(name);
	}

	private static class NameCondition<B extends HasName, T extends NamedBaseTree<B, T>>
			implements Node.Condition<B, T> {

		private final String name;

		private NameCondition(final String name) {
			this.name = name;
		}

		@Override
		public boolean isSatisfied(final Node<B, T> node) {
			return name.equals(node.getBase().getName());
		}
	}

	/**
	 * @param name
	 *            non <code>null</code> name of child to find
	 * @return the first child with the given <code>name</code>, or
	 *         <code>null</code>, if there is none
	 */
	public Node<B, T> findNamedChild(final String name) {
		return findChildSatisfying(new NameCondition<B, T>(name));
	}

	/**
	 * @param name
	 *            non <code>null</code> name of children to find
	 * @return a set of all the children with the given <code>name</code>
	 */
	public Set<Node<B, T>> findAllNamedChildren(final String name) {
		return findAllChildrenSatisfying(new NameCondition<B, T>(name));
	}

	/**
	 * @param name
	 *            non <code>null</code> name of descendant to find
	 * @return the first descendant with the given <code>name</code>, or
	 *         <code>null</code>, if there is none
	 */
	public Node<B, T> findNamedDescendant(final String name) {
		return findDescendantSatisfying(new NameCondition<B, T>(name));
	}

	/**
	 * @param name
	 *            non <code>null</code> name of descendant to find
	 * @return a set of all the descendants with the given <code>name</code>
	 */
	public Set<Node<B, T>> findAllNamedDescendants(final String name) {
		return findAllDescendantsSatisfying(new NameCondition<B, T>(name));
	}
}
